const state = {
    names: [],
    matrix: [],
    result: null,
    steps: [],
    stepIdx: 0,
    playing: false,
    timer: null,
    speedMs: 800,
    positions: [],
    mstCost: 0
};

// DOM refs
const fileInput = document.getElementById('fileInput');
const loadSampleBtn = document.getElementById('loadSampleBtn');
const dataStatus = document.getElementById('dataStatus');
const runBtn = document.getElementById('runBtn');
const runStatus = document.getElementById('runStatus');
const graph = document.getElementById('graph');
const buildingCountEl = document.getElementById('buildingCount');
const totalCostEl = document.getElementById('totalCost');
const algoNameEl = document.getElementById('algoName');
const playBtn = document.getElementById('playBtn');
const pauseBtn = document.getElementById('pauseBtn');
const nextBtn = document.getElementById('nextBtn');
const resetBtn = document.getElementById('resetBtn');
const speedRange = document.getElementById('speedRange');
const stepsList = document.getElementById('stepsList');
const downloadBtn = document.getElementById('downloadBtn');

// Utils
function parseCSV(text) {
    const lines = text.trim().split(/\r?\n/);
    const names = lines[0].split(',').map(s => s.trim());
    const matrix = [];
    for (let i = 1; i < lines.length; i++) {
        matrix.push(lines[i].split(',').map(Number));
    }
    return { names, matrix };
}

function getSelectedAlgo() {
    const radios = document.querySelectorAll('input[name="algo"]');
    for (const r of radios) if (r.checked) return r.value;
    return 'prim';
}

function clearSVG() {
    graph.innerHTML = '';
}

function computePositions(names) {
    const width = graph.viewBox.baseVal.width || graph.clientWidth;
    const height = graph.viewBox.baseVal.height || graph.clientHeight;
    const cx = width / 2, cy = height / 2;
    const r = Math.min(width, height) * 0.38;
    const pos = [];
    const n = names.length;
    for (let i = 0; i < n; i++) {
        const ang = (2 * Math.PI * i) / n - Math.PI / 2;
        pos.push({ x: cx + r * Math.cos(ang), y: cy + r * Math.sin(ang) });
    }
    return pos;
}

function drawNodes(names, positions) {
    const gNodes = document.createElementNS('http://www.w3.org/2000/svg', 'g');
    gNodes.setAttribute('id', 'nodes');
    graph.appendChild(gNodes);

    names.forEach((name, i) => {
        const p = positions[i];

        const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
        circle.setAttribute('cx', p.x);
        circle.setAttribute('cy', p.y);
        circle.setAttribute('r', 18);
        circle.setAttribute('fill', '#ffb3a7');
        circle.setAttribute('stroke', '#aa4a44');
        circle.setAttribute('stroke-width', '2');
        gNodes.appendChild(circle);

        const label = document.createElementNS('http://www.w3.org/2000/svg', 'text');
        label.setAttribute('x', p.x);
        label.setAttribute('y', p.y - 24);
        label.setAttribute('text-anchor', 'middle');
        label.setAttribute('font-size', '12px');
        label.textContent = name;
        gNodes.appendChild(label);
    });

    const gMST = document.createElementNS('http://www.w3.org/2000/svg', 'g');
    gMST.setAttribute('id', 'mstEdges');
    graph.appendChild(gMST);

    const gConsider = document.createElementNS('http://www.w3.org/2000/svg', 'g');
    gConsider.setAttribute('id', 'considerEdges');
    graph.appendChild(gConsider);
}

function drawEdge(u, v, weight, opts = { permanent: false, color: '#1f77b4', width: 2, dashed: false }) {
    const positions = state.positions;
    const p1 = positions[u], p2 = positions[v];

    const gTargetId = opts.permanent ? 'mstEdges' : 'considerEdges';
    const gTarget = document.getElementById(gTargetId);
    if (!opts.permanent) {
        gTarget.innerHTML = ''; // 清理前一个 consider
    }

    const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
    line.setAttribute('x1', p1.x);
    line.setAttribute('y1', p1.y);
    line.setAttribute('x2', p2.x);
    line.setAttribute('y2', p2.y);
    line.setAttribute('stroke', opts.color);
    line.setAttribute('stroke-width', opts.width);
    if (opts.dashed) {
        line.setAttribute('stroke-dasharray', '6,4');
    }
    gTarget.appendChild(line);

    const midx = (p1.x + p2.x) / 2;
    const midy = (p1.y + p2.y) / 2;
    const label = document.createElementNS('http://www.w3.org/2000/svg', 'text');
    label.setAttribute('x', midx);
    label.setAttribute('y', midy - 6);
    label.setAttribute('text-anchor', 'middle');
    label.setAttribute('font-size', '11px');
    label.setAttribute('fill', opts.color);
    label.textContent = `${Math.round(weight)}m`;
    gTarget.appendChild(label);
}

function logStep(step) {
    const li = document.createElement('li');
    if (step.type === 'consider') {
        li.textContent = step.description;
    } else if (step.type === 'select') {
        li.textContent = step.description;
    } else if (step.type === 'reject') {
        li.textContent = `拒绝边 ${state.names[step.u]} ←→ ${state.names[step.v]}（${Math.round(step.weight)}m）：${step.reason}`;
    }
    stepsList.appendChild(li);
    li.scrollIntoView({ behavior: 'smooth', block: 'end' });
}

function applyStep(step) {
    if (step.type === 'consider') {
        drawEdge(step.u, step.v, step.weight, { permanent: false, color: '#888', width: 2, dashed: true });
    } else if (step.type === 'select') {
        drawEdge(step.u, step.v, step.weight, { permanent: true, color: '#d62728', width: 4 });
        state.mstCost += step.weight;
        totalCostEl.textContent = Math.round(state.mstCost);
    } else if (step.type === 'reject') {
        drawEdge(step.u, step.v, step.weight, { permanent: false, color: '#bbb', width: 2, dashed: true });
    }
    logStep(step);
}

function nextStep() {
    if (!state.result || state.stepIdx >= state.steps.length) return;
    applyStep(state.steps[state.stepIdx]);
    state.stepIdx += 1;
    if (state.stepIdx >= state.steps.length) {
        runStatus.textContent = '完成';
        document.getElementById('considerEdges').innerHTML = '';
    }
}

function play() {
    if (!state.result || state.playing) return;
    state.playing = true;
    state.timer = setInterval(() => {
        if (state.stepIdx < state.steps.length) {
            nextStep();
        } else {
            pause();
        }
    }, state.speedMs);
}

function pause() {
    state.playing = false;
    if (state.timer) {
        clearInterval(state.timer);
        state.timer = null;
    }
}

function reset() {
    pause();
    state.stepIdx = 0;
    state.mstCost = 0;
    totalCostEl.textContent = '0';
    stepsList.innerHTML = '';
    const mst = document.getElementById('mstEdges');
    const consider = document.getElementById('considerEdges');
    if (mst) mst.innerHTML = '';
    if (consider) consider.innerHTML = '';
}

function updateStats() {
    buildingCountEl.textContent = state.names.length;
    totalCostEl.textContent = Math.round(state.result?.total_cost || 0);
    algoNameEl.textContent = state.result?.algorithm || '-';
}

function downloadSummary() {
    if (!state.result) return;
    const algo = state.result.algorithm;
    const total = Math.round(state.result.total_cost);
    const edges = state.result.mst_edges.map((e, i) => {
        const uName = state.names[e.u];
        const vName = state.names[e.v];
        const w = Math.round(e.weight);
        return `${i + 1}. ${uName} ←→ ${vName} : ${w} 米`;
    }).join('\n');

    const stepsText = state.steps.map((s, i) => {
        if (s.type === 'consider') return `${i + 1}. 考虑边：${state.names[s.u]} ←→ ${state.names[s.v]}（${Math.round(s.weight)}m）`;
        if (s.type === 'select') return `${i + 1}. 选择边：${state.names[s.u]} ←→ ${state.names[s.v]}（${Math.round(s.weight)}m）`;
        return `${i + 1}. 拒绝边：${state.names[s.u]} ←→ ${state.names[s.v]}（${Math.round(s.weight)}m），原因：${s.reason}`;
    }).join('\n');

    const text = `${algo}算法最优管线铺设方案\n总铺设距离: ${total} 米\n铺设路径详情:\n${edges}\n\n生成过程:\n${stepsText}`;
    const blob = new Blob([text], { type: 'text/plain;charset=utf-8' });
    const a = document.createElement('a');
    a.href = URL.createObjectURL(blob);
    a.download = 'pipeline_solution.txt';
    a.click();
    URL.revokeObjectURL(a.href);
}

// Event bindings
fileInput.addEventListener('change', async (ev) => {
    const file = ev.target.files[0];
    if (!file) return;
    const text = await file.text();
    const { names, matrix } = parseCSV(text);
    state.names = names;
    state.matrix = matrix;
    state.positions = computePositions(names);
    dataStatus.textContent = `已加载：${names.length} 个建筑`;
    clearSVG();
    drawNodes(names, state.positions);
    reset();
});

loadSampleBtn.addEventListener('click', async () => {
    const res = await fetch('/api/sample');
    const json = await res.json();
    if (json.error) {
        dataStatus.textContent = `加载失败：${json.error}`;
        return;
    }
    state.names = json.names;
    state.matrix = json.matrix;
    state.positions = computePositions(state.names);
    dataStatus.textContent = `已加载示例：${state.names.length} 个建筑`;
    clearSVG();
    drawNodes(state.names, state.positions);
    reset();
});

runBtn.addEventListener('click', async () => {
    if (!state.names.length || !state.matrix.length) {
        runStatus.textContent = '请先加载CSV';
        return;
    }
    reset();
    runStatus.textContent = '计算中...';

    const algo = getSelectedAlgo();
    const res = await fetch('/api/compute', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ algorithm: algo, names: state.names, matrix: state.matrix })
    });
    const json = await res.json();
    if (json.error) {
        runStatus.textContent = `失败：${json.error}`;
        return;
    }
    state.result = json;
    state.steps = json.steps;
    state.mstCost = 0;
    updateStats();
    runStatus.textContent = `已就绪（${algo.toUpperCase()}）`;
});

playBtn.addEventListener('click', play);
pauseBtn.addEventListener('click', pause);
nextBtn.addEventListener('click', nextStep);
resetBtn.addEventListener('click', reset);
speedRange.addEventListener('input', (e) => {
    state.speedMs = Number(e.target.value);
    if (state.playing) {
        pause();
        play();
    }
});
downloadBtn.addEventListener('click', downloadSummary);

// 初始提示
clearSVG();